// Helper function to get the unique values of an array based 
//  a property accessor function propFunc
Array.prototype.unique = function(propFunc) {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[propFunc(this[i])] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};
// Used to do reverse lookup on the term id since the term id in the database is not logical
var terms = Array();
terms[0] = {TermID:5, Semester:"Summer", Year:2004};
terms[1] = {TermID:6, Semester:"Fall", Year:2004};
terms[2] = {TermID:7, Semester:"Spring", Year:2005};
terms[3] = {TermID:8, Semester:"Summer", Year:2005};
terms[4] = {TermID:9, Semester:"Fall", Year:2005};
terms[5] = {TermID:10, Semester:"Spring", Year:2006};
terms[6] = {TermID:11, Semester:"Summer", Year:2006};
terms[7] = {TermID:12, Semester:"Fall", Year:2006};
terms[8] = {TermID:13, Semester:"Spring", Year:2007};
terms[9] = {TermID:14, Semester:"Summer", Year:2007};
terms[10] = {TermID:15, Semester:"Fall", Year:2007};
terms[11] = {TermID:16, Semester:"Spring", Year:2008};
terms[12] = {TermID:17, Semester:"Summer", Year:2008};
terms[13] = {TermID:18, Semester:"Fall", Year:2008};
terms[14] = {TermID:3, Semester:"Spring", Year:2009};
terms[15] = {TermID:4, Semester:"Summer", Year:2009};
terms[16] = {TermID:1, Semester:"Fall", Year:2009};
terms[17] = {TermID:2, Semester:"Spring", Year:2010};
terms[18] = {TermID:19, Semester:"Summer", Year:2010};

// Main function to render scatter plot
function scatterplot() {
	// Create a new root panel to render the visualization in
	vis_scat = new pv.Panel();
	
	var marginL = 30, // Left margin
		marginR = 50, // Right margin
		// Make the visualization as big as possible without overlapping interactions area
		w = winW-marginL-marginR-interactionsWidth-60,  
		// Make the height 70% of the window height winH
		h = winH*0.70,
		// Create a range for the 20 semesters from 0 to 19
		termRange = pv.range(0, 19),
		// Crate an ordinal scale based on the range of semesters split across the total
		//  width of the visualization
		x = pv.Scale.ordinal(termRange).split(0, w),
		// Create a linear scale from 0 to 4.1 (slightly higher than the max gpa of 4
		y = pv.Scale.linear(0, 4.1).range(0, h),
		// Create a default color base
		c = pv.Colors.category10(),
		// Font information
		labelFont = "10pt Sans Serif";

	// Set main properties of visualization
	vis_scat.width(w)
		.height(h)
		.left(marginL)
		.right(marginR)
		.bottom(20)
		.top(20)
		.strokeStyle("#ccc") // Set to gray stroke around the visualization
		.def("i", -1);
	
	// Add the x-axis based on terms
	vis_scat.add(pv.Rule)
		.data(terms)
		.strokeStyle("#eee")
		.left(function() x(this.index) ) // Compute the left position based on the index
	  .anchor("bottom").add(pv.Label) // Add a label
	  	// Add first two characters of semester and year
		.text(function(d) d.Semester[0] + d.Semester[1] + d.Year)
		.font(labelFont);

	// Add y-axis which is from 0 to 4.1
	vis_scat.add(pv.Rule)
		.data(y.ticks()) // Use computed y axis ticks
		.strokeStyle("#eee")
		.bottom(y) // Use values in y to make position from bottom of vis
	  .anchor("left").add(pv.Label)
		.font(labelFont);

	// Create legened, add a dot for every unique professor
	var profs = vis_scat.add(pv.Dot)  
		// Get the unique professors and then sort them alphabetically
		.data(function() data.unique(function(d) d.ProfessorID).sort(function(a, b) {
			if(a.LastName == b.LastName) {
				return 0;
			} else if (a.LastName > b.LastName) {
				return 1;
			} else {
				return -1;
			}
		} ))
		// Shift left 155 pixels every 5 professors
		.left(function(d) Math.floor(this.index/5)*155 + 20)
		// Move down 20 pixels in each column every new index
		.bottom(function(d) 100 - (this.index%5)*20)
		// Set stroke style and fill style based on professor ID and color scale "c"
		.strokeStyle(function(d) c(d.ProfessorID))
		// Change the fill style to have 1 alpha when someone is hovering over this professor
		.fillStyle(function(d) vis_scat.i() == d.ProfessorID ? c(d.ProfessorID).alpha(1) : c(d.ProfessorID).alpha(0.4))
		.size(60)
		// Add event to change the i variable used for highlighting the professor's dots
		.event("mouseover", function(d) vis_scat.i(d.ProfessorID))
		// Reset i variable
		.event("mouseout", function(d) vis_scat.i(-1));
		
	// Add a text label of the professors name to the right of the professor's dot
	profs.anchor("right").add(pv.Label)
		.font(labelFont)
		.textBaseline("middle")
		.text(function(d) d.LastName + ", " + d.FirstName);

	// Render averages as a horizontal line (rule)
	var avg = profs.add(pv.Rule)
		// Make them start at the left and go the full width of the vis
		.left(0)
		.width(w)
		// Compute the bottom position by finding the average of the professor
		.bottom(function(d) {
			var count = 0;
			var sum = 0;
			// Loop through all the data and add professor's scores
			for(var i = 0; i < data.length; i++) {
				// Only add to the sum if the professor id of the current data
				//  matches the professor
				if(d.ProfessorID == data[i].ProfessorID) {
					sum = sum + parseFloat(data[i].GPA);
					count = count + 1;
				}
			}
			return y(sum/count);
		})
		// Set color based on color scale "c"
		.strokeStyle(function(d) c(d.ProfessorID))
		// Only make visible when the i variable equals the professor's id
		.visible(function(d) vis_scat.i() == d.ProfessorID ? true : false);

	// Add text label for average on right side of the graph
	avg.anchor("right").add(pv.Label)
		// Compute the average like above but output "AVG:" as well
		.text(function(d) {
			var count = 0;
			var sum = 0;
			for(var i = 0; i < data.length; i++) {
				if(d.ProfessorID == data[i].ProfessorID) {
					sum = sum + parseFloat(data[i].GPA);
					count = count + 1;
				}
			}
			var roundLength = 2;
			var avg = sum/count;
			return "AVG: " + Math.round(avg*Math.pow(10,roundLength))/Math.pow(10,roundLength);
		});
		
	// Add text label for average on the left side of the graph
	avg.anchor("left").add(pv.Label)
		.text(function(d) {
			var count = 0;
			var sum = 0;
			for(var i = 0; i < data.length; i++) {
				if(d.ProfessorID == data[i].ProfessorID) {
					sum = sum + parseFloat(data[i].GPA);
					count = count + 1;
				}
			}
			var roundLength = 2;
			var avg = sum/count;
			return Math.round(avg*Math.pow(10,roundLength))/Math.pow(10,roundLength);
		});
		
	// Render actual GPAs as dots
	var gpa = vis_scat.add(pv.Dot)
		.data(function() data)
		// Find the correct in order term id based on the TermID given since TermIDs are not in order
		.left(function(d) {
			var reverseId = -1;
			for(var i = 0; i < terms.length; i++) {
				// Check to see if the logical array term id is the same as the current term id
				if(terms[i].TermID == d.TermID) {
					reverseId = i;
					break;
				}
			}
			return x(reverseId);
		})
		// Set bottom based on y scale and GPA
		.bottom(function(d) y(d.GPA))
		// Set the size based on the size of the class
		//  A special case of 5 when the class size is "very large 55-999"
		.size(function(d) { if(d.SizeID == 5) return d.SizeID*40; else return d.SizeID*17; })
		// Set color based on professor
		.strokeStyle(function(d) c(d.ProfessorID))
		// Set opacity based on whether the professor is being hovered
		.fillStyle(function(d) vis_scat.i() == d.ProfessorID ? c(d.ProfessorID).alpha(1) : c(d.ProfessorID).alpha(0.4))
		// Set variable i on hover and reset on mouseout
		.event("mouseover", function(d) vis_scat.i(d.ProfessorID))
		.event("mouseout", function(d) vis_scat.i(-1))
		// Load pie chart when clicked
		.event("click", function(d) openMyModal('pie.php?sectionID=' + d.SectionID));
		
	// Add an anchor to the right of all the dots only
	gpa.anchor("right").add(pv.Label)
		.text(function(d) d.GPA)
		// Only let them be visible when the current professor is hovered
		.visible(function(d) vis_scat.i() == d.ProfessorID ? true : false);
	
	// Render the visualization
	vis_scat.render();
}

